﻿using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;

using System.Security.Cryptography;
//using System.IO.Compression;
using System.IO;
using Ionic.BZip2;

namespace Urd.Packet
{
    
    public class packet
    {
       // crc
       // HashAlgorithm hasher;
        Header header;
        public long timestamp;
        public int ID { get { return GetInt(0); } }
        public int Size { get { return 3 + size; } }
        private byte size;
        public string Someinfo { 
            get
            {
                string ret =Encoding.UTF8.GetString(data.ToArray(),0,data.ToArray().Length);
                if (ret != "") return ret.Remove(ret.IndexOf('\0'));
                else return ret;
            }
        }
        List<byte> data;
        public string debug { get { return header.code.ToString() + "," + header.command.ToString() + ",[i:]" + GetInt(0).ToString() + "," + GetFloat(1).ToString() + "," + GetFloat(2).ToString() + "," + GetFloat(3).ToString(); } }
        public string debug2 
        {
            get 
            {
                string ret = "";
                
                ret += header.code+" ";
                ret += header.command + " ";
                ret += 3 + data.Count + "\n";
                for (int i = 0; i < data.Count-3; i += 4) 
                {
                    float f = BitConverter.ToSingle(data.ToArray(),i);
                    if (!float.IsNaN(f)&&(f>0.001f||f<-0.001f)) ret +="f:"+f.ToString()+"\n";
                    else 
                    {
                        ret +="i:"+ BitConverter.ToInt32(data.ToArray(), i).ToString()+"\n";
                    }
                }
                return ret;
            }
        }
     
        public packet(byte[] recieved)
        {
           // hasher.
            if (recieved.Length > 2)
            {
                byte[] temp = recieved;
                // byte[] temp = recieved.ToArray();
                header = new Header((Opcode)temp[0], (Command)temp[1]);
                size = temp[2];
                //opcode = (Opcode)temp[0];
                data = new List<byte>(128);
                //   id = BitConverter.ToInt16(temp, 1);
                
               // using (DeflateStream dc = new DeflateStream(
                for (int i = 3; i < recieved.Length; i++)
                {
                    data.Add(temp[i]);
                }
            }
            else 
            {
                header = new Header(Opcode.Undefined,Command.None);
                
                data = new List<byte>();
            }
        }

        public packet(Opcode o, Command c)
        {
            header = new Header(o, c);
            data = new List<byte>(4);
            size = 6;
        }
        public packet(Opcode o)
        {
            header = new Header(o, Command.None);
            data = new List<byte>(4);
            size = 6;
        }
        public void Push(float num)
        {
            size += sizeof(float);
            data.AddRange(BitConverter.GetBytes(num));
        }
        public void Push(int num)
        {
            size += sizeof(int);
            data.AddRange(BitConverter.GetBytes(num));
        }
        public void Push(uint num)
        {
            size += sizeof(uint);
            data.AddRange(BitConverter.GetBytes(num));
        }
        public void Push(string what)
        {
            data.Clear();
            data.AddRange(Encoding.UTF8.GetBytes(what.ToCharArray()));
            size = (byte)data.Count;
        }

        public byte[] Bytes
        {
            get
            {
                List<byte> ret = new List<byte>();
                ret.Add((byte)header.code);
                ret.Add((byte)header.command);
                //timestamp
                //ret.AddRange(BitConverter.GetBytes(DateTime.Now.Ticks));
                //size
                ret.Add((byte)data.Count);
                ret.AddRange(data);
                return ret.ToArray();                
            }
        }
        public Opcode code { get { return header.code; } }
        public Command command { get { return header.command; } set { header.command = value; } }
        // to remake
        public float GetFloat(int index)
        {
            if (index < data.Count/sizeof(float))
            {
                return BitConverter.ToSingle(data.ToArray(),index*sizeof(float));
            }
            else return 0f;
        }
        public int GetInt(int index)
        {
            if (index < data.Count / sizeof(int))
            {
                return BitConverter.ToInt32(data.ToArray(), index*sizeof(int));
            }
            else return 0;
        }
        public int IntCount { get { return data.Count / sizeof(int); } }
        public float FloatCount { get { return data.Count / sizeof(float); } }

     



    }

    //pack 
    /// <summary>
    /// 1-st packet is header and always persist;
    /// there is 
    /// 1 byte - managerinfo-opcode so topmanager can handle packet
    /// 1 byte - post get packet - command
    /// 8 byte timestamp
    /// 4 byte packet num
    /// </summary>
  

  
   



}
